#include "Rotate.h"
#include "Utility.h"
namespace RayTracer
{
	RotateY::RotateY(std::shared_ptr<Hitable> p, float angle) : ptr(p)
	{
        auto radians = glm::radians(angle);
        sin_theta = sin(radians);
        cos_theta = cos(radians);
        hasbox = ptr->BoundingBox(bbox);

        vec3 min(infinity, infinity, infinity);
        vec3 max(-infinity, -infinity, -infinity);

        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                for (int k = 0; k < 2; k++) {
                    auto x = i * bbox.Max().x + (1 - i) * bbox.Min().x;
                    auto y = j * bbox.Max().y + (1 - j) * bbox.Min().y;
                    auto z = k * bbox.Max().z + (1 - k) * bbox.Min().z;

                    auto newx = cos_theta * x + sin_theta * z;
                    auto newz = -sin_theta * x + cos_theta * z;

                    vec3 tester(newx, y, newz);

                    for (int c = 0; c < 3; c++) {
                        min[c] = fmin(min[c], tester[c]);
                        max[c] = fmax(max[c], tester[c]);
                    }
                }
            }
        }

        bbox = AABB(min, max);
	}

	bool RotateY::Hit(const Ray& r, float t_min, float t_max, HitRecord& rec) const
	{
        auto origin = r.origin();
        auto direction = r.direction();

        origin[0] = cos_theta * r.origin()[0] - sin_theta * r.origin()[2];
        origin[2] = sin_theta * r.origin()[0] + cos_theta * r.origin()[2];

        direction[0] = cos_theta * r.direction()[0] - sin_theta * r.direction()[2];
        direction[2] = sin_theta * r.direction()[0] + cos_theta * r.direction()[2];

        Ray rotated_r(origin, direction);

        if (!ptr->Hit(rotated_r, t_min, t_max, rec))
            return false;

        auto p = rec.position;
        auto normal = rec.normal;

        p[0] = cos_theta * rec.position[0] + sin_theta * rec.position[2];
        p[2] = -sin_theta * rec.position[0] + cos_theta * rec.position[2];

        normal[0] = cos_theta * rec.normal[0] + sin_theta * rec.normal[2];
        normal[2] = -sin_theta * rec.normal[0] + cos_theta * rec.normal[2];

        rec.position = p;
        rec.set_face_normal(rotated_r, normal);

        return true;
	}
}